package com.hippo.core.util;

import com.alibaba.druid.pool.DruidDataSourceFactory;
import lombok.extern.slf4j.Slf4j;

import javax.sql.DataSource;
import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author hippo
 */
@Slf4j
public class DruidConnectionPool {

    private static DataSource dataSource;

    public DruidConnectionPool(String driver, String url, String username, String password) {
        HashMap<Object, Object> objectObjectHashMap = new HashMap<>();
        objectObjectHashMap.put("driver", driver);
        objectObjectHashMap.put("url", url);
        objectObjectHashMap.put("username", username);
        objectObjectHashMap.put("password", password);
        try {
            dataSource = DruidDataSourceFactory.createDataSource(objectObjectHashMap);
        } catch (Exception e) {
            throw new RuntimeException("druid连接池初始化失败...");
        }
    }

    public static DataSource getDataSource() {
        return dataSource;
    }

    public Connection getConnection() {
        Connection connection = null;
        try {
            connection = dataSource.getConnection();
            log.info("database-链接成功");
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return connection;
    }

    public static void release(ResultSet resultSet, Statement statement, Connection connection) {
        // 关闭ResultSet
        if (resultSet != null) {
            try {
                resultSet.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        // 关闭Statement
        if (statement != null) {
            try {
                statement.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        // 关闭Connection
        if (connection != null) {
            try {
                statement.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    public static void release(Statement statement, Connection connection) {
        release(null, statement, connection);
    }


    public static StringBuilder getPrefixByDbType(String dbType, String tableName, StringBuilder fields) {
        StringBuilder prefix = new StringBuilder();
        if (dbType.equals("mysql")) {
            prefix.append("INSERT INTO ")
                    .append("`" + tableName + "`")
                    .append(" (")
                    .append(fields)
                    .append(" )  VALUES ");
        } else {
            prefix.append("INSERT INTO `" + tableName + "` (" + fields + ") VALUES ");
        }
        return prefix;
    }

    public static int executeUpdate(Connection connection, String sql, Object[] bindArgs) throws SQLException {
        //影响的行数
        int affectRowCount = -1;
        PreparedStatement preparedStatement = null;
        try {
            //执行SQL预编译
            preparedStatement = connection.prepareStatement(sql);
//            log.info("预编译SQL：" + getExecSql(sql, bindArgs));
            //绑定参数设置sql占位符中的值
            if (bindArgs != null) {
                for (int i = 0; i < bindArgs.length; i++) {
                    preparedStatement.setObject(i + 1, bindArgs[i]);
                }
            }
//            log.info(preparedStatement.toString());
            //执行sql
            affectRowCount = preparedStatement.executeUpdate();
//            connection.commit();
        } catch (Exception e) {
//            if (connection != null) {
//                //自动提交功能设置为启用时无法回退
//                connection.rollback();
//            }
            e.printStackTrace();
            throw e;
        } finally {
            if (preparedStatement != null) {
                preparedStatement.close();
            }
        }
        return affectRowCount;
    }

    public static List<Map<String, Object>> executeQuery(
            String driver, String url, String username, String password, String sql, Object[] bindArgs
    ) throws Exception {
        long startTime = System.currentTimeMillis();
        List<Map<String, Object>> datas = new ArrayList<>();
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        try {
            //获取数据库连接池中的连接
            connection = new DruidConnectionPool(driver, url, username, password).getConnection();
            preparedStatement = connection.prepareStatement(sql);
            if (bindArgs != null && bindArgs[0].toString().length() != 0) {
                //设置sql占位符中的值
                for (int i = 0; i < bindArgs.length; i++) {
                    preparedStatement.setObject(i + 1, bindArgs[i]);
                }
            }
//            log.info(getExecSql(sql, bindArgs));
            //执行sql语句，获取结果集
            resultSet = preparedStatement.executeQuery();
            datas = getDatas(resultSet);
        } catch (Exception e) {
            e.printStackTrace();
            throw e;
        } finally {
            DruidConnectionPool.release(resultSet, preparedStatement, connection);
            log.info("database-连接关闭");
            long endTime = System.currentTimeMillis();
            log.info("程序运行时间：" + (endTime - startTime) + "ms");
        }
        return datas;
    }

    private static List<Map<String, Object>> getDatas(ResultSet resultSet) throws SQLException {
        List<Map<String, Object>> datas = new ArrayList<>();
        //获取结果集的数据结构对象
        ResultSetMetaData metaData = resultSet.getMetaData();
        while (resultSet.next()) {
            Map<String, Object> rowMap = new HashMap<>();
            for (int i = 1; i <= metaData.getColumnCount(); i++) {
                rowMap.put(metaData.getColumnName(i), resultSet.getObject(i));
            }
            datas.add(rowMap);
        }
        log.info("成功查询到了" + datas.size() + "行数据");
        for (int i = 0; i < datas.size(); i++) {
            Map<String, Object> map = datas.get(i);
        }
        return datas;
    }

    private static String getExecSql(String sql, Object[] bindArgs) {
        StringBuilder sb = new StringBuilder(sql);
        if (bindArgs != null && bindArgs.length > 0 && bindArgs[0].toString().length() != 0) {
            int index = 0;
            for (int i = 0; i < bindArgs.length; i++) {
                index = sb.indexOf("?", index);
                sb.replace(index, index + 1, String.valueOf(bindArgs[i]));
            }
        }
        return sb.toString();
    }

}
